// bsls_alignment.h                                                   -*-C++-*-
#ifndef INCLUDED_BSLS_ALIGNMENT
#define INCLUDED_BSLS_ALIGNMENT

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a namespace for enumerating memory alignment strategies.
//
//@CLASSES:
//  bsls::Alignment: namespace for enumerated alignment strategy values
//
//@SEE_ALSO: bsls_alignmentutil
//
//@DESCRIPTION: This component provides a namespace, `bsls::Alignment`, for
// enumerating alignment strategies, and provides a function, `toAscii`, that
// converts each of the enumerators to its corresponding string representation.
//
///Alignment Strategy
///------------------
// This component supports three alignment strategies: 1) MAXIMUM ALIGNMENT,
// 2) NATURAL ALIGNMENT, and 3) 1-BYTE ALIGNMENT.
//
// 1. MAXIMUM ALIGNMENT: This strategy, as indicated by the enumerator
//    `BSLS_MAXIMUM`, specifies that a memory block be aligned as per the
//    *most* restrictive alignment requirement on the host platform.
// 2. NATURAL ALIGNMENT: This strategy, as indicated by the enumerator
//    `BSLS_NATURAL`, specifies that a memory block be aligned based on the
//    size (in bytes) of that block.  An object of a fundamental type (`int`,
//    etc.) is *naturally* *aligned* when its size evenly divides its address.
//    An object of an aggregate type has natural alignment if the alignment of
//    the most-restrictively aligned sub-object evenly divides the address of
//    the aggregate.  Natural alignment is always at least as restrictive as
//    the compiler's required alignment.
// 3. 1-BYTE ALIGNMENT: This strategy, as indicated by the enumerator
//    `BSLS_BYTEALIGNED`, specifies that a memory block may be aligned
//    arbitrarily on any 1-byte boundary.  This is the *least* restrictive
//    alignment requirement.
//
///Usage
///-----
// Suppose that we want to create a static function, `allocateFromBuffer`, that
// takes a buffer, the size of the buffer, a cursor indicating a position
// within the buffer, an allocation request size, and a memory alignment
// strategy; `allocateFromBuffer` returns a pointer to a block of memory,
// wholly contained within the buffer, having the specified size and alignment.
// As a side-effect, the cursor is updated to refer to the next available free
// byte in the buffer.  Such a function could be used by a memory manager to
// satisfy allocation requests from internally-managed buffers.  Clients of
// this function indicate which alignment strategy to use based on their
// specific requirements.
//
// Our `allocateFromBuffer` function depends on an alignment utility,
// `my_AlignmentUtil`, whose minimal interface is limited to that required by
// this usage example.  (See the `bsls_alignmentutil` component for a more
// realistic alignment utility.):
// ```
// struct my_AlignmentUtil {
//     // This 'struct' provides a namespace for basic types and utilities
//     // related to memory alignment.
//
//     // TYPES
//
//     /// Provide the *minimal* value that satisfies the alignment
//     /// requirements for *all* types on the host platform.  Note that 8
//     /// is used for illustration purposes only; an actual implementation
//     /// would employ template meta-programming to deduce the value at
//     /// compile time.
//     enum {
//         MY_MAX_PLATFORM_ALIGNMENT = 8
//     };
//
//     // CLASS METHODS
//
//     /// Calculate a usable alignment for a memory block of the specified
//     /// `size` (in bytes) in the absence of compile-time knowledge of
//     /// the block's alignment requirements.  Return the largest power of
//     /// two that evenly divides `size`, up to a maximum of
//     /// `MY_MAX_PLATFORM_ALIGNMENT`.  It is guaranteed that a block of
//     /// `size` bytes can be safely aligned on the return value.   The
//     /// behavior is undefined unless `0 < size`.
//     static int calculateAlignmentFromSize(int size);
//
//     /// Return the smallest non-negative offset (in bytes) that, when
//     /// added to the specified `address`, yields the specified
//     /// `alignment`.  The behavior is undefined unless `0 != alignment`
//     /// and `alignment` is a non-negative, integral power of 2.
//     static int calculateAlignmentOffset(const void *address,
//                                         int         alignment);
// };
// ```
// The definition of our `allocateFromBuffer` function is as follows:
// ```
// /// Allocate a memory block of the specified `size` (in bytes) from the
// /// specified `buffer` having the specified `bufferSize` at the
// /// specified `cursor` position, using the specified alignment
// /// `strategy`.  Return the address of the allocated memory block if
// /// `buffer` contains sufficient available memory, and 0 otherwise.  The
// /// `cursor` is set to the first byte position immediately after the
// /// allocated memory (which might be 1 byte past the end of `buffer`) if
// /// there is sufficient memory, and is not modified otherwise.  The
// /// behavior is undefined unless `0 <= bufferSize`, `0 < size`, and
// /// `cursor` refers to a valid position in `buffer`.
// static void *allocateFromBuffer(int                       *cursor,
//                                 char                      *buffer,
//                                 int                        bufferSize,
//                                 int                        size,
//                                 bsls::Alignment::Strategy  strategy)
// {
// ```
// First we assert the function pre-conditions:
// ```
//     assert(cursor);
//     assert(buffer);
//     assert(0 <= bufferSize);
//     assert(0 < size);
// ```
// Then, based on the alignment `strategy`, we calculate the alignment value
// that can satisfy the allocation request.  In the case of
// `bsls::Alignment::BSLS_NATURAL`, we calculate the alignment from `size`; for
// `bsls::Alignment::BSLS_MAXIMUM`, we use the platform-dependent
// `my_AlignmentUtil::MY_MAX_PLATFORM_ALIGNMENT` value; and for
// `bsls::Alignment::BSLS_BYTEALIGNED`, we simply use 1:
// ```
//     const int alignment =
//                        strategy == bsls::Alignment::BSLS_NATURAL
//                        ? my_AlignmentUtil::calculateAlignmentFromSize(size)
//                        : strategy == bsls::Alignment::BSLS_MAXIMUM
//                          ? my_AlignmentUtil::MY_MAX_PLATFORM_ALIGNMENT
//                          : 1;
// ```
// Now we calculate the offset from the current `cursor` value that can satisfy
// the `alignment` requirements:
// ```
//     const int offset = my_AlignmentUtil::calculateAlignmentOffset(
//                                                           buffer + *cursor,
//                                                           alignment);
//
// ```
// Next we check if the available free memory in `buffer` can satisfy the
// allocation request; 0 is returned if the request cannot be satisfied:
// ```
//     if (*cursor + offset + size > bufferSize) {
//         return 0;                                                 // RETURN
//     }
//
//     void *result = &buffer[*cursor + offset];
//     *cursor += offset + size;
//
// ```
// Finally, return the address of the correctly aligned memory block:
// ```
//     return result;
// }
// ```
// The `allocateFromBuffer` function may be used by a memory manager that needs
// to appropriately align memory blocks that are allocated from
// internally-managed buffers.  For an example, see the `bslma_bufferimputil`
// component.

#ifndef BDE_OMIT_INTERNAL_DEPRECATED

#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
#include <bsls_alignmentfromtype.h>
#include <bsls_alignmentimp.h>
#include <bsls_alignmenttotype.h>
#include <bsls_platform.h>

#include <cstddef>      // for std::size_t
#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES

// Temporarily define the legacy 'bsls_AlignmentOf' to refer to its
// replacement, 'bsls::AlignmentFromType'.

#ifndef bsls_AlignmentOf
#define bsls_AlignmentOf bsls::AlignmentFromType
#endif

// required for some code below wrapped in ifndef BDE_OMIT_INTERNAL_DEPRECATED

#include <bsls_alignmentutil.h>
#endif // BDE_OMIT_INTERNAL_DEPRECATED

namespace BloombergLP {

namespace bsls {

                        // ================
                        // struct Alignment
                        // ================

/// This `struct` provides a namespace for enumerating the set of strategies
/// for aligning arbitrary blocks of memory.
struct Alignment {

    // TYPES

    /// Types of alignment strategy.
    enum Strategy {
        /// Align memory block based on the most restrictive alignment
        /// requirements of the host platform.
        BSLS_MAXIMUM = 0,

        /// Align memory block on an address that is the largest power of
        /// two that evenly divides the size (in bytes) of the block.
        BSLS_NATURAL = 1,

        /// Align memory block based on the least restrictive alignment
        /// requirements of the host platform (1-byte aligned).
        BSLS_BYTEALIGNED = 2
    };

#ifndef BDE_OMIT_INTERNAL_DEPRECATED
    /// Define the minimum alignment that satisfies all types.
    ///
    /// @DEPRECATED: This `enum` is deprecated.  Use
    /// `AlignmentUtil::BSLS_MAX_ALIGNMENT` instead.
    enum {
        MAX_ALIGNMENT = AlignmentUtil::BSLS_MAX_ALIGNMENT
    };

    /// Primitive type with most stringent alignment requirement.
    ///
    /// @DEPRECATED: Use `AlignmentUtil::MaxAlignedType` instead.
    typedef AlignmentUtil::MaxAlignedType MaxAlignedType;

    /// `struct` with most stringent alignment requirement.
    ///
    /// @DEPRECATED: Use `Alignment::MaxAlignedType` instead.
    struct Align {
        MaxAlignedType d_align;
    };
#endif // BDE_OMIT_INTERNAL_DEPRECATED

    // CLASS METHODS

    /// Return the string representation of the specified enumerator
    /// `value`.  The string representation of `value` matches its
    /// corresponding enumerator name with the "BSLS_" prefix elided.  For
    /// example:
    /// ```
    /// bsl::cout << Alignment::toAscii(Alignment::BSLS_NATURAL);
    /// ```
    /// will print the following on standard output:
    /// ```
    /// NATURAL
    /// ```
    static const char *toAscii(Alignment::Strategy value);

#ifndef BDE_OMIT_INTERNAL_DEPRECATED
    /// Calculate a usable alignment for an object of specified `size` bytes
    /// in the absence of compile-time knowledge of the object's alignment
    /// requirements.  Return the largest power of two that evenly divides
    /// size, up to a maximum of `MAX_ALIGNMENT`.  It is guaranteed that an
    /// object of `size` bytes can be safely aligned on this return value.
    /// Depending on the machine architecture and compiler options, the
    /// returned alignment may be more than required for two reasons:
    /// ```
    ///   1. The object may be composed entirely of elements, such as
    ///      'char', which have minimal alignment restrictions.
    ///
    ///   2. The architecture may have lenient alignment requirements.
    ///      Even if this is the case, aligning on a stricter boundary may
    ///      improve performance.
    /// ```
    /// The behavior is undefined unless `0 < size`.
    ///
    /// @DEPRECATED: Use `AlignmentUtil::calculateAlignmentFromSize` instead.
    static int calculateAlignmentFromSize(int size);

    /// Return the smallest non-negative offset in bytes that, when added to
    /// the specified `address`, yields the specified `alignment`.  The
    /// behavior is undefined unless `0 < alignment` and `alignment` is a
    /// power of 2.
    ///
    /// @DEPRECATED: Use `AlignmentUtil::calculateAlignmentOffset` instead.
    static int calculateAlignmentOffset(const void *address, int alignment);

    /// Return `true` if the specified `address` is aligned on a 2-byte
    /// boundary (i.e., the integer value of `address` is divisible by 2),
    /// and `false` otherwise.
    ///
    /// @DEPRECATED: Use `AlignmentUtil::is2ByteAligned` instead.
    static bool is2ByteAligned(const void *address);

    /// Return `true` if the specified `address` is aligned on a 4-byte
    /// boundary (i.e., the integer value of `address` is divisible by 4),
    /// and `false` otherwise.
    ///
    /// @DEPRECATED: Use `AlignmentUtil::is4ByteAligned` instead.
    static bool is4ByteAligned(const void *address);

    /// Return `true` if the specified `address` is aligned on an 8-byte
    /// boundary (i.e., the integer value of `address` is divisible by 8),
    /// and `false` otherwise.
    ///
    /// @DEPRECATED: Use `AlignmentUtil::is8ByteAligned` instead.
    static bool is8ByteAligned(const void *address);
#endif // BDE_OMIT_INTERNAL_DEPRECATED
};

}  // close package namespace

#ifndef BDE_OMIT_INTERNAL_DEPRECATED

namespace bsls {

// ============================================================================
//                      INLINE FUNCTION DEFINITIONS
// ============================================================================

                            // ----------------
                            // struct Alignment
                            // ----------------

// CLASS METHODS
inline
int Alignment::calculateAlignmentFromSize(int size)
{
    return AlignmentUtil::calculateAlignmentFromSize(size);
}

inline
int Alignment::calculateAlignmentOffset(const void *address,
                                        int         alignment)
{
    return AlignmentUtil::calculateAlignmentOffset(address, alignment);
}

inline
bool Alignment::is2ByteAligned(const void *address)
{
    return AlignmentUtil::is2ByteAligned(address);
}

inline
bool Alignment::is4ByteAligned(const void *address)
{
    return AlignmentUtil::is4ByteAligned(address);
}

inline
bool Alignment::is8ByteAligned(const void *address)
{
    return AlignmentUtil::is8ByteAligned(address);
}

}  // close package namespace

#endif // BDE_OMIT_INTERNAL_DEPRECATED

#ifndef BDE_OPENSOURCE_PUBLICATION  // BACKWARD_COMPATIBILITY
// ============================================================================
//                           BACKWARD COMPATIBILITY
// ============================================================================

/// This alias is defined for backward compatibility.
typedef bsls::Alignment bsls_Alignment;
#endif  // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY

}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2013 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
